﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

namespace CardPlay.Model.CardModel
{
    public class Dealer : IDealContext
    {
        private readonly IList<Card> _deck;
        private readonly Action<Card, string> _dealAction;

        public Dealer(IList<Card> deck, Action<Card, string> dealAction)
        {
            Contract.Requires<ArgumentNullException>(deck != null);
            Contract.Requires<ArgumentNullException>(dealAction != null);

            _deck = deck;
            _dealAction = dealAction;
        }

        public void Deal(IDealAction script)
        {
            if (script == null) return;

            while (!script.Execute(this))
            {
                ++Step;
            }
        }

        public uint Step
        {
            get; private set;
        }

        bool IDealContext.IsDeckEmpty
        {
            get { return _deck.Count == 0; }
        }

        void IDealContext.DealCard(Predicate<CardFace> selectCard, CardOrientation orientation, string toPile)
        {
            var card = _deck.FirstOrDefault(item => selectCard(item));
            Guard.Against<InvalidOperationException>(card == null, "No matching card exists in the deck.");

            DealCard(card, orientation, toPile);
        }

        void IDealContext.DealCard(Predicate<CardFace> selectCard, CardOrientation orientation, Func<Card, string> targetSelector)
        {
            var card = _deck.FirstOrDefault(item => selectCard(item));
            Guard.Against<InvalidOperationException>(card == null, "No matching card exists in the deck.");

            DealCard(card, orientation, targetSelector(card));
        }

        private void DealCard(Card card, CardOrientation orientation, string targetPile)
        {
            Contract.Requires(card != null);
            Contract.Requires(targetPile != null);

            card.Orientation = orientation;

            _deck.Remove(card);
            _dealAction(card, targetPile);
        }
    }
}